package com.pcbly.web.components.utils.decorator;

import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Decorator;
import com.opensymphony.module.sitemesh.DecoratorMapper;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper;
import com.opensymphony.module.sitemesh.mapper.DefaultDecorator;
import com.opensymphony.module.sitemesh.mapper.PathMapper;

@SuppressWarnings("unchecked")
public class DynamicDecoratorMapper extends ConfigDecoratorMapper {
	protected ConcurrentHashMap decorators;
	protected PathMapper pathMapper;
	private static ConcurrentLinkedQueue extraDecorators = new ConcurrentLinkedQueue();
	private static ConcurrentLinkedQueue extraExcludedPaths = new ConcurrentLinkedQueue();

	public static class DecoratorBean {

		private String name;
		private String page;
		private String pattern;

		public DecoratorBean(String name, String page, String pattern) {
			this.name = name;
			this.page = page;
			this.pattern = pattern;
		}
	}

	public DynamicDecoratorMapper() {
		decorators = new ConcurrentHashMap();
		pathMapper = new PathMapper();
	}

	public void init(Config config, Properties properties,
			DecoratorMapper parent) throws InstantiationException {
		super.init(config, properties, parent);
		updateDecorators();
		updateExcludedPaths();
	}

	private void updateDecorators() {
		DecoratorBean bean;
		while ((bean = (DecoratorBean) extraDecorators.poll()) != null)
			addDecorator(bean.name, bean.page, bean.pattern);
	}

	private void updateExcludedPaths() {
		String path;
		while ((path = (String) extraExcludedPaths.poll()) != null)
			addExclude(path);
	}

	public Decorator getDecorator(HttpServletRequest request, Page page) {
		Decorator decorator = super.getDecorator(request, page);
		if (decorator != null)
			return decorator;
		String thisPath = request.getServletPath();
		if (thisPath == null) {
			String requestURI = request.getRequestURI();
			if (request.getPathInfo() != null)
				thisPath = requestURI.substring(0, requestURI.indexOf(request
						.getPathInfo()));
			else
				thisPath = requestURI;
		} else if (thisPath.equals("") && request.getPathInfo() != null)
			thisPath = request.getPathInfo();
		updateDecorators();
		String name = pathMapper.get(thisPath);
		return getNamedDecorator(request, name);
	}

	public Decorator getNamedDecorator(HttpServletRequest request, String name) {
		if (StringUtils.isEmpty(name)) {
			String thisPath = request.getServletPath();
			if (thisPath == null) {
				String requestURI = request.getRequestURI();
				if (request.getPathInfo() != null)
					thisPath = requestURI.substring(0, requestURI
							.indexOf(request.getPathInfo()));
				else
					thisPath = requestURI;
			} else if (thisPath.equals("") && request.getPathInfo() != null)
				thisPath = request.getPathInfo();
			updateDecorators();
			name = pathMapper.get(thisPath);
		}
		Decorator result = super.getNamedDecorator(request, name);
		if (result != null)
			return result;
		if (StringUtils.isEmpty(name))
			return null;
		else
			return (Decorator) decorators.get(name);
	}

	public void addDecorator(String name, String page, String pattern) {
		String uriPath = null;
		Map params = null;
		String role = null;
		Decorator d = new DefaultDecorator(name, page, uriPath, role, params);
		decorators.put(name, d);
		pathMapper.put(name, pattern);
	}

	
	public Collection getDecorators() {
		updateDecorators();
		return decorators.values();
	}

	public void addExclude(String path) {
		LightSoftSitemeshFactory factory = (LightSoftSitemeshFactory) LightSoftSitemeshFactory
				.getInstance(config);
		factory.addExcludeUrl(path);
	}

	public PathMapper getExcludes() {
		updateExcludedPaths();
		LightSoftSitemeshFactory factory = (LightSoftSitemeshFactory) LightSoftSitemeshFactory
				.getInstance(config);
		return factory.getExcludeURLs();
	}

	public boolean isPathExcluded(String path) {
		updateExcludedPaths();
		LightSoftSitemeshFactory factory = (LightSoftSitemeshFactory) LightSoftSitemeshFactory
				.getInstance(config);
		return factory.isPathExcluded(path);
	}

	public static void addDecoratorBean(DecoratorBean bean) {
		extraDecorators.add(bean);
	}

	public static void addExcludedPath(String path) {
		extraExcludedPaths.add(path);
	}

}
